/*
 * MIT License
 *
 * Copyright (c) 2024-2048 冰羽
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package cn.star.framework.es.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.star.framework.core.api.AppResult;
import cn.star.framework.core.api.Pageable;
import cn.star.framework.es.core.EsQueryBuilder;
import cn.star.framework.es.core.Sorter;
import cn.star.framework.es.core.Where;
import cn.star.framework.es.core.WhereGroup;
import cn.star.framework.es.entity.IndexWrapper;
import cn.star.framework.es.service.IService;
import cn.star.framework.es.support.HttpServletRequestQueryBuilder;
import cn.star.framework.type.QueryType;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

/**
 * Mvc抽象层<br>
 *
 * @author zhaoweiping
 *     <p style='color: red'>Created on 2024-09-23 11:06:00
 * @since 3.0.0
 */
@Slf4j
public abstract class AbstractController {

  /** 索引名称 */
  protected abstract String getIndexName();

  /** CRUD */
  protected abstract IService getService();

  @Deprecated
  protected HttpServletRequestQueryBuilder getQueryBuilder() {
    HttpServletRequest request =
        ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes()))
            .getRequest();

    return this.getQueryBuilder(request);
  }

  protected HttpServletRequestQueryBuilder getQueryBuilder(HttpServletRequest request) {
    return new HttpServletRequestQueryBuilder(request);
  }

  /**
   * {@link PostMapping}
   *
   * @param entity - {@link ResponseBody}
   * @return {@link AppResult}
   */
  public AppResult<String> save(Map<String, Object> entity) {
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setData(CollectionUtil.newArrayList(entity));
    wrapper = this.getService().save(wrapper);

    return AppResult.ofSuccess();
  }

  /**
   * {@link PutMapping}
   *
   * @param entity - {@link ResponseBody}
   * @return {@link AppResult}
   */
  public AppResult<String> update(Map<String, Object> entity) {
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setData(CollectionUtil.newArrayList(entity));
    wrapper = this.getService().update(wrapper);

    return AppResult.ofSuccess();
  }

  private List<Map<String, Object>> getPrimaryKeys(String... ids) {
    return CollectionUtil.newArrayList(ids).stream()
        .map(
            id -> {
              Map<String, Object> data = new HashMap<>(1);
              data.put(IndexWrapper.PRIMARY_KEY, id);
              return data;
            })
        .collect(Collectors.toList());
  }

  /**
   * {@link DeleteMapping}
   *
   * @param ids - {@link ResponseBody}
   * @return {@link AppResult}
   */
  public AppResult<?> deleteByIds(String... ids) {
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setData(this.getPrimaryKeys(ids));
    wrapper = this.getService().delete(wrapper);

    return AppResult.ofSuccess();
  }

  /**
   * {@link GetMapping}
   *
   * @param request {@link HttpServletRequest}
   * @return {@link AppResult}
   */
  public AppResult<List<Map<String, Object>>> list(HttpServletRequest request) {
    EsQueryBuilder queryBuilder = this.getQueryBuilder(request);
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setQueryBuilder(queryBuilder);

    List<Map<String, Object>> data = this.getService().find(wrapper);

    return AppResult.ofSuccess(data);
  }

  /**
   * {@link GetMapping}/id
   *
   * @param id - {@link PathVariable}
   * @return {@link AppResult}
   */
  public AppResult<Map<String, Object>> get(String id, HttpServletRequest request) {
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setQueryBuilder(this.getQueryBuilder(request));

    Map<String, Object> data = this.getService().findById(wrapper, id);

    return AppResult.ofSuccess(data);
  }

  /**
   * 查询树叶子节点数据
   *
   * @param index 索引
   * @param id 主键值
   * @param parent 父节点数据字段名称
   * @return 叶子节点集合，若不是树而获取叶子节点则抛出异常
   */
  public List<Map<String, Object>> getChildren(String index, Object id, String parent) {
    IndexWrapper wrapper = new IndexWrapper(index);
    wrapper.setQueryBuilder(
        new EsQueryBuilder() {
          @Override
          public List<WhereGroup> getWhereGroups() {
            return CollectionUtil.newArrayList(
                new WhereGroup(CollectionUtil.newArrayList(new Where(parent, QueryType.EQ, id))));
          }

          @Override
          public List<Sorter> getSorters() {
            return Collections.emptyList();
          }

          @Override
          public List<String> getQueryColumns() {
            return Collections.emptyList();
          }
        });

    return this.getService().find(wrapper);
  }

  /**
   * {@link GetMapping}/page
   *
   * @param request {@link HttpServletRequest}
   * @return {@link AppResult} {@link Pageable}
   */
  public AppResult<Pageable<Map<String, Object>>> pageable(HttpServletRequest request) {
    HttpServletRequestQueryBuilder queryBuilder = this.getQueryBuilder(request);
    IndexWrapper wrapper = new IndexWrapper(this.getIndexName());
    wrapper.setQueryBuilder(queryBuilder);

    Pageable<Map<String, Object>> pageable =
        this.getService().pageable(wrapper, queryBuilder.getPageNo(), queryBuilder.getPageSize());

    return AppResult.ofSuccess(pageable);
  }

  /**
   * 数据导入
   *
   * @param tmp 文件临时目录
   * @param file 数据文件
   * @return {@link AppResult}
   */
  @SneakyThrows
  @SuppressWarnings("all")
  public AppResult<String> imp(String tmp, MultipartFile file) {
    // TODO 暂未实现

    return AppResult.ofSuccess();
  }

  /**
   * 数据导出
   *
   * @param request {@link HttpServletRequest}
   * @param response {@link HttpServletResponse}
   */
  public void exp(HttpServletRequest request, HttpServletResponse response) {
    // TODO 暂未实现
  }
}
